package com.zp.container;


import com.alibaba.fastjson.JSON;
import com.zp.domain.RegisterDo;
import com.zp.dto.request.RegisterReq;
import com.zp.util.CommonConstant;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author zp
 * @description 我的注册容器
 * @created 2021/11/24 9:43
 */


@Component
public class MyRegisterContainer {
    private static final Log log = LogFactory.getLog(MyRegisterContainer.class);

    private volatile Map<String, HashSet<RegisterDo>> registerMap = new ConcurrentHashMap<>();

    private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

    public MyRegisterContainer(){
        log.info("初始化注册容器，启动心跳检测....");
        //每隔3秒检测一次
        scheduledExecutorService.scheduleAtFixedRate(new HeartBeatThread(),3,3, TimeUnit.SECONDS);
    }


    /**
     * 装载注册服务
     *
     * @param registerReq
     * @return
     */
    public boolean put(RegisterReq registerReq) {
        //首先获取服务名称对应的服务列表
        HashSet<RegisterDo> registerDos = registerMap.get(registerReq.getServiceName());
        //双重检验锁判定容器是否存在
        if (registerDos == null) {
            synchronized (this) {
                if (registerDos == null) {
                    registerDos = new HashSet<>();
                    registerMap.put(registerReq.getServiceName(), registerDos);
                }
            }
        }
        RegisterDo registerDo = new RegisterDo(registerReq.getServiceName()
                , registerReq.getServiceAddrUrl(), CommonConstant.REGISTER_STATE_AVTIVE
                , System.currentTimeMillis());
        return registerDos.add(registerDo);
    }

    /**
     * 剔除注册服务
     *
     * @return
     */
    public boolean remove(RegisterReq registerReq) {
        log.info("剔除注册服务："+JSON.toJSONString(registerReq));
        return findByRegisterDo(registerReq,true)!=null;
    }

    /**
     * 寻找registerDo
     * @param registerReq
     * @return
     */
    private RegisterDo findByRegisterDo(RegisterReq registerReq){
        return findByRegisterDo(registerReq,false);
    }
    /**
     * 寻找registerDo
     * @param registerReq
     * @param isDelete
     * @return
     */
    private RegisterDo findByRegisterDo(RegisterReq registerReq, boolean isDelete){
        HashSet<RegisterDo> registerDos = registerMap.get(registerReq.getServiceName());
        if(registerDos != null){
            Optional<RegisterDo> any = registerDos.stream()
                    .filter(registerDo -> registerDo.getServiceAddrUrl()
                            .equals(registerReq.getServiceAddrUrl())).findAny();
            if(any.isPresent()){
                RegisterDo registerDo = any.get();
                if(isDelete){
                    registerDos.remove(registerDo);
                }
                return registerDo;
            }
        }
        return null;
    }

    /**
     * 活跃服务
     *
     * @return
     */
    public Map<String, HashSet<RegisterDo>> activeService() {
        return registerMap;
    }

    /**
     * 服务续约
     * @param registerReq
     */
    public boolean renewal(RegisterReq registerReq){
        RegisterDo byRegisterDo = findByRegisterDo(registerReq);
        if(byRegisterDo == null){
            log.info("没有找到续约的服务，重新装载");
            put(registerReq);
        }else{
            long currentTimeMillis = System.currentTimeMillis();
            log.info("服务续约，默认为当前时间："+currentTimeMillis);
            byRegisterDo.setLastRenewalTime(currentTimeMillis);
        }
        return true;
    }

    /**
     * 心跳检测，剔除下线
     */
    class HeartBeatThread implements Runnable{

        @Override
        public void run() {
            registerMap.forEach((serviceName,registerDos)->{
                long currentTimeMillis = System.currentTimeMillis();
                Set<RegisterDo> collect = registerDos.stream().filter(registerDo -> {
                    long overTime = currentTimeMillis - registerDo.getLastRenewalTime();
                    if(overTime > CommonConstant.DELETEIP_TIMEOUT){
                        log.info("服务名称：" + registerDo.getServiceName() + "," +
                                "服务地址" + registerDo.getServiceAddrUrl() + ",当前系统时间:" + currentTimeMillis
                                + ",该服务上一次续约时间" + registerDo.getLastRenewalTime() + "服务被剔除.");
                        return true;
                    }
                    return false;
                }).collect(Collectors.toSet());
                //筛选出超出时间的服务，进行删除处理
                log.info("将要删除的服务集合："+JSON.toJSONString(collect));
                registerDos.removeAll(collect);
            });
            log.info("当前活跃服务："+ JSON.toJSONString(registerMap));
        }
    }
}
